// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//

#include <cantor/type/tree.h>
#include <gtest/gtest.h>

#include <cantor/type/type.h>
#include <cantor/type/type_kind.h>

int main(int argc, char *argv[]) {
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

namespace cantor {
    TEST(type, type_trait) {
        /// boolean
        {
            using Type = TypeTraits<pb::TypeKind::TYPE_KIND_BOOLEAN>;
            ASSERT_TRUE((std::is_same_v<Type::impl_type, ScalarType<pb::TypeKind::TYPE_KIND_BOOLEAN>>));
            ASSERT_TRUE((std::is_same_v<Type::physical_type, bool>));
            ASSERT_TRUE((std::is_same_v<Type::deep_copied_type, bool>));
            ASSERT_EQ(Type::min_sub_types, 0);
            ASSERT_EQ(Type::max_sub_types, 0);
            ASSERT_EQ(Type::typeKind, pb::TypeKind::TYPE_KIND_BOOLEAN);
            ASSERT_EQ(Type::primitive_type, PrimitiveType::BOOLEAN | PrimitiveType::PRIMITIVE);
            ASSERT_EQ(Type::is_fixed_width, true);
            ASSERT_EQ(std::string(Type::name), "BOOLEAN");
        }
        /// INT8
        {
            using Type = TypeTraits<pb::TypeKind::TYPE_KIND_INT8>;
            ASSERT_TRUE((std::is_same_v<Type::impl_type, ScalarType<pb::TypeKind::TYPE_KIND_INT8>>));
            ASSERT_TRUE((std::is_same_v<Type::physical_type, int8_t>));
            ASSERT_TRUE((std::is_same_v<Type::deep_copied_type, int8_t>));
            ASSERT_EQ(Type::min_sub_types, 0);
            ASSERT_EQ(Type::max_sub_types, 0);
            ASSERT_EQ(Type::typeKind, pb::TypeKind::TYPE_KIND_INT8);
            ASSERT_EQ(Type::primitive_type, PrimitiveType::INTEGER | PrimitiveType::PRIMITIVE);
            ASSERT_EQ(Type::is_fixed_width, true);
            ASSERT_EQ(std::string(Type::name), "INT8");
        }
        /// INT16
        {
            using Type = TypeTraits<pb::TypeKind::TYPE_KIND_INT16>;
            ASSERT_TRUE((std::is_same_v<Type::impl_type, ScalarType<pb::TypeKind::TYPE_KIND_INT16>>));
            ASSERT_TRUE((std::is_same_v<Type::physical_type, int16_t>));
            ASSERT_TRUE((std::is_same_v<Type::deep_copied_type, int16_t>));
            ASSERT_EQ(Type::min_sub_types, 0);
            ASSERT_EQ(Type::max_sub_types, 0);
            ASSERT_EQ(Type::typeKind, pb::TypeKind::TYPE_KIND_INT16);
            ASSERT_EQ(Type::primitive_type, PrimitiveType::INTEGER | PrimitiveType::PRIMITIVE);
            ASSERT_EQ(Type::is_fixed_width, true);
            ASSERT_EQ(std::string(Type::name), "INT16");
        }
        /// INT32
        {
            using Type = TypeTraits<pb::TypeKind::TYPE_KIND_INT32>;
            ASSERT_TRUE((std::is_same_v<Type::impl_type, ScalarType<pb::TypeKind::TYPE_KIND_INT32>>));
            ASSERT_TRUE((std::is_same_v<Type::physical_type, int32_t>));
            ASSERT_TRUE((std::is_same_v<Type::deep_copied_type, int32_t>));
            ASSERT_EQ(Type::min_sub_types, 0);
            ASSERT_EQ(Type::max_sub_types, 0);
            ASSERT_EQ(Type::typeKind, pb::TypeKind::TYPE_KIND_INT32);
            ASSERT_EQ(Type::primitive_type, PrimitiveType::INTEGER | PrimitiveType::PRIMITIVE);
            ASSERT_EQ(Type::is_fixed_width, true);
            ASSERT_EQ(std::string(Type::name), "INT32");
        }
        /// INT64
        {
            using Type = TypeTraits<pb::TypeKind::TYPE_KIND_INT64>;
            ASSERT_TRUE((std::is_same_v<Type::impl_type, ScalarType<pb::TypeKind::TYPE_KIND_INT64>>));
            ASSERT_TRUE((std::is_same_v<Type::physical_type, int64_t>));
            ASSERT_TRUE((std::is_same_v<Type::deep_copied_type, int64_t>));
            ASSERT_EQ(Type::min_sub_types, 0);
            ASSERT_EQ(Type::max_sub_types, 0);
            ASSERT_EQ(Type::typeKind, pb::TypeKind::TYPE_KIND_INT64);
            ASSERT_EQ(Type::primitive_type, PrimitiveType::INTEGER | PrimitiveType::PRIMITIVE);
            ASSERT_EQ(Type::is_fixed_width, true);
            ASSERT_EQ(std::string(Type::name), "INT64");
        }
        /// INT128
        {
            using Type = TypeTraits<pb::TypeKind::TYPE_KIND_INT128>;
            ASSERT_TRUE((std::is_same_v<Type::impl_type, ScalarType<pb::TypeKind::TYPE_KIND_INT128>>));
            ASSERT_TRUE((std::is_same_v<Type::physical_type, turbo::int128>));
            ASSERT_TRUE((std::is_same_v<Type::deep_copied_type, turbo::int128>));
            ASSERT_EQ(Type::min_sub_types, 0);
            ASSERT_EQ(Type::max_sub_types, 0);
            ASSERT_EQ(Type::typeKind, pb::TypeKind::TYPE_KIND_INT128);
            ASSERT_EQ(Type::primitive_type, PrimitiveType::INTEGER | PrimitiveType::PRIMITIVE);
            ASSERT_EQ(Type::is_fixed_width, true);
            ASSERT_EQ(std::string(Type::name), "INT128");
        }
        /// UINT8
        {
            using Type = TypeTraits<pb::TypeKind::TYPE_KIND_UINT8>;
            ASSERT_TRUE((std::is_same_v<Type::impl_type, ScalarType<pb::TypeKind::TYPE_KIND_UINT8>>));
            ASSERT_TRUE((std::is_same_v<Type::physical_type, uint8_t>));
            ASSERT_TRUE((std::is_same_v<Type::deep_copied_type, uint8_t>));
            ASSERT_EQ(Type::min_sub_types, 0);
            ASSERT_EQ(Type::max_sub_types, 0);
            ASSERT_EQ(Type::typeKind, pb::TypeKind::TYPE_KIND_UINT8);
            ASSERT_EQ(Type::primitive_type, PrimitiveType::INTEGER | PrimitiveType::PRIMITIVE);
            ASSERT_EQ(Type::is_fixed_width, true);
            ASSERT_EQ(std::string(Type::name), "UINT8");
        }
        /// UINT16
        {
            using Type = TypeTraits<pb::TypeKind::TYPE_KIND_UINT16>;
            ASSERT_TRUE((std::is_same_v<Type::impl_type, ScalarType<pb::TypeKind::TYPE_KIND_UINT16>>));
            ASSERT_TRUE((std::is_same_v<Type::physical_type, uint16_t>));
            ASSERT_TRUE((std::is_same_v<Type::deep_copied_type, uint16_t>));
            ASSERT_EQ(Type::min_sub_types, 0);
            ASSERT_EQ(Type::max_sub_types, 0);
            ASSERT_EQ(Type::typeKind, pb::TypeKind::TYPE_KIND_UINT16);
            ASSERT_EQ(Type::primitive_type, PrimitiveType::INTEGER | PrimitiveType::PRIMITIVE);
            ASSERT_EQ(Type::is_fixed_width, true);
            ASSERT_EQ(std::string(Type::name), "UINT16");
        }
        /// UINT32
        {
            using Type = TypeTraits<pb::TypeKind::TYPE_KIND_UINT32>;
            ASSERT_TRUE((std::is_same_v<Type::impl_type, ScalarType<pb::TypeKind::TYPE_KIND_UINT32>>));
            ASSERT_TRUE((std::is_same_v<Type::physical_type, uint32_t>));
            ASSERT_TRUE((std::is_same_v<Type::deep_copied_type, uint32_t>));
            ASSERT_EQ(Type::min_sub_types, 0);
            ASSERT_EQ(Type::max_sub_types, 0);
            ASSERT_EQ(Type::typeKind, pb::TypeKind::TYPE_KIND_UINT32);
            ASSERT_EQ(Type::primitive_type, PrimitiveType::INTEGER | PrimitiveType::PRIMITIVE);
            ASSERT_EQ(Type::is_fixed_width, true);
            ASSERT_EQ(std::string(Type::name), "UINT32");
        }
        /// UINT64
        {
            using Type = TypeTraits<pb::TypeKind::TYPE_KIND_UINT64>;
            ASSERT_TRUE((std::is_same_v<Type::impl_type, ScalarType<pb::TypeKind::TYPE_KIND_UINT64>>));
            ASSERT_TRUE((std::is_same_v<Type::physical_type, uint64_t>));
            ASSERT_TRUE((std::is_same_v<Type::deep_copied_type, uint64_t>));
            ASSERT_EQ(Type::min_sub_types, 0);
            ASSERT_EQ(Type::max_sub_types, 0);
            ASSERT_EQ(Type::typeKind, pb::TypeKind::TYPE_KIND_UINT64);
            ASSERT_EQ(Type::primitive_type, PrimitiveType::INTEGER | PrimitiveType::PRIMITIVE);
            ASSERT_EQ(Type::is_fixed_width, true);
            ASSERT_EQ(std::string(Type::name), "UINT64");
        }
        /// UINT128
        {
            using Type = TypeTraits<pb::TypeKind::TYPE_KIND_UINT128>;
            ASSERT_TRUE((std::is_same_v<Type::impl_type, ScalarType<pb::TypeKind::TYPE_KIND_UINT128>>));
            ASSERT_TRUE((std::is_same_v<Type::physical_type, turbo::uint128>));
            ASSERT_TRUE((std::is_same_v<Type::deep_copied_type, turbo::uint128>));
            ASSERT_EQ(Type::min_sub_types, 0);
            ASSERT_EQ(Type::max_sub_types, 0);
            ASSERT_EQ(Type::typeKind, pb::TypeKind::TYPE_KIND_UINT128);
            ASSERT_EQ(Type::primitive_type, PrimitiveType::INTEGER | PrimitiveType::PRIMITIVE);
            ASSERT_EQ(Type::is_fixed_width, true);
            ASSERT_EQ(std::string(Type::name), "UINT128");
        }
        /// FP8
        {
            using Type = TypeTraits<pb::TypeKind::TYPE_KIND_FP8>;
            ASSERT_TRUE((std::is_same_v<Type::impl_type, ScalarType<pb::TypeKind::TYPE_KIND_FP8>>));
            ASSERT_TRUE((std::is_same_v<Type::physical_type, uint8_t>));
            ASSERT_TRUE((std::is_same_v<Type::deep_copied_type, uint8_t>));
            ASSERT_EQ(Type::min_sub_types, 0);
            ASSERT_EQ(Type::max_sub_types, 0);
            ASSERT_EQ(Type::typeKind, pb::TypeKind::TYPE_KIND_FP8);
            ASSERT_EQ(Type::primitive_type, PrimitiveType::FLOAT | PrimitiveType::PRIMITIVE);
            ASSERT_EQ(Type::is_fixed_width, true);
            ASSERT_EQ(std::string(Type::name), "FP8");
        }
        /// FP16
        {
            using Type = TypeTraits<pb::TypeKind::TYPE_KIND_FP16>;
            ASSERT_TRUE((std::is_same_v<Type::impl_type, ScalarType<pb::TypeKind::TYPE_KIND_FP16>>));
            ASSERT_TRUE((std::is_same_v<Type::physical_type, uint16_t>));
            ASSERT_TRUE((std::is_same_v<Type::deep_copied_type, uint16_t>));
            ASSERT_EQ(Type::min_sub_types, 0);
            ASSERT_EQ(Type::max_sub_types, 0);
            ASSERT_EQ(Type::typeKind, pb::TypeKind::TYPE_KIND_FP16);
            ASSERT_EQ(Type::primitive_type, PrimitiveType::FLOAT | PrimitiveType::PRIMITIVE);
            ASSERT_EQ(Type::is_fixed_width, true);
            ASSERT_EQ(std::string(Type::name), "FP16");
        }
        /// FP32
        {
            using Type = TypeTraits<pb::TypeKind::TYPE_KIND_FP32>;
            ASSERT_TRUE((std::is_same_v<Type::impl_type, ScalarType<pb::TypeKind::TYPE_KIND_FP32>>));
            ASSERT_TRUE((std::is_same_v<Type::physical_type, float>));
            ASSERT_TRUE((std::is_same_v<Type::deep_copied_type, float>));
            ASSERT_EQ(Type::min_sub_types, 0);
            ASSERT_EQ(Type::max_sub_types, 0);
            ASSERT_EQ(Type::typeKind, pb::TypeKind::TYPE_KIND_FP32);
            ASSERT_EQ(Type::primitive_type, PrimitiveType::FLOAT | PrimitiveType::PRIMITIVE);
            ASSERT_EQ(Type::is_fixed_width, true);
            ASSERT_EQ(std::string(Type::name), "FP32");
        }
        /// FP64
        {
            using Type = TypeTraits<pb::TypeKind::TYPE_KIND_FP64>;
            ASSERT_TRUE((std::is_same_v<Type::impl_type, ScalarType<pb::TypeKind::TYPE_KIND_FP64>>));
            ASSERT_TRUE((std::is_same_v<Type::physical_type, double>));
            ASSERT_TRUE((std::is_same_v<Type::deep_copied_type, double>));
            ASSERT_EQ(Type::min_sub_types, 0);
            ASSERT_EQ(Type::max_sub_types, 0);
            ASSERT_EQ(Type::typeKind, pb::TypeKind::TYPE_KIND_FP64);
            ASSERT_EQ(Type::primitive_type, PrimitiveType::FLOAT | PrimitiveType::PRIMITIVE);
            ASSERT_EQ(Type::is_fixed_width, true);
            ASSERT_EQ(std::string(Type::name), "FP64");
        }
        /// STRING
        {
            using Type = TypeTraits<pb::TypeKind::TYPE_KIND_STRING>;
            ASSERT_TRUE((std::is_same_v<Type::impl_type, StringType>));
            ASSERT_TRUE((std::is_same_v<Type::physical_type, std::string_view>));
            ASSERT_TRUE((std::is_same_v<Type::deep_copied_type, std::string>));
            ASSERT_EQ(Type::min_sub_types, 0);
            ASSERT_EQ(Type::max_sub_types, 0);
            ASSERT_EQ(Type::typeKind, pb::TypeKind::TYPE_KIND_STRING);
            ASSERT_EQ(Type::primitive_type, PrimitiveType::STRING | PrimitiveType::PRIMITIVE);
            ASSERT_EQ(Type::is_fixed_width, false);
            ASSERT_EQ(std::string(Type::name), "STRING");
        }

        /// BINARY
        {
            using Type = TypeTraits<pb::TypeKind::TYPE_KIND_BINARY>;
            ASSERT_TRUE((std::is_same_v<Type::impl_type, BinaryType>));
            ASSERT_TRUE((std::is_same_v<Type::physical_type, std::string_view>));
            ASSERT_TRUE((std::is_same_v<Type::deep_copied_type, std::string>));
            ASSERT_EQ(Type::min_sub_types, 0);
            ASSERT_EQ(Type::max_sub_types, 0);
            ASSERT_EQ(Type::typeKind, pb::TypeKind::TYPE_KIND_BINARY);
            ASSERT_EQ(Type::primitive_type, PrimitiveType::STRING | PrimitiveType::PRIMITIVE);
            ASSERT_EQ(Type::is_fixed_width, false);
            ASSERT_EQ(std::string(Type::name), "BINARY");
        }
        /// TIMESTAMP
        {
            using Type = TypeTraits<pb::TypeKind::TYPE_KIND_TIMESTAMP>;
            ASSERT_TRUE((std::is_same_v<Type::impl_type, TimestampType>));
            ASSERT_TRUE((std::is_same_v<Type::physical_type, turbo::Time>));
            ASSERT_TRUE((std::is_same_v<Type::deep_copied_type, int64_t>));
            ASSERT_EQ(Type::min_sub_types, 0);
            ASSERT_EQ(Type::max_sub_types, 0);
            ASSERT_EQ(Type::typeKind, pb::TypeKind::TYPE_KIND_TIMESTAMP);
            ASSERT_EQ(Type::primitive_type, PrimitiveType::TIME | PrimitiveType::PRIMITIVE);
            ASSERT_EQ(Type::is_fixed_width, true);
            ASSERT_EQ(std::string(Type::name), "TIMESTAMP");
        }
        /// DURATION
        {
            using Type = TypeTraits<pb::TypeKind::TYPE_KIND_DURATION>;
            ASSERT_TRUE((std::is_same_v<Type::impl_type, DurationType>));
            ASSERT_TRUE((std::is_same_v<Type::physical_type, turbo::Duration>));
            ASSERT_TRUE((std::is_same_v<Type::deep_copied_type, int64_t>));
            ASSERT_EQ(Type::min_sub_types, 0);
            ASSERT_EQ(Type::max_sub_types, 0);
            ASSERT_EQ(Type::typeKind, pb::TypeKind::TYPE_KIND_DURATION);
            ASSERT_EQ(Type::primitive_type, PrimitiveType::TIME | PrimitiveType::PRIMITIVE);
            ASSERT_EQ(Type::is_fixed_width, true);
            ASSERT_EQ(std::string(Type::name), "DURATION");
        }
        /// DATETIME
        {
            using Type = TypeTraits<pb::TypeKind::TYPE_KIND_DATETIME>;
            ASSERT_TRUE((std::is_same_v<Type::impl_type, DateTimeType>));
            ASSERT_TRUE((std::is_same_v<Type::physical_type, turbo::CivilSecond>));
            ASSERT_TRUE((std::is_same_v<Type::deep_copied_type, int64_t>));
            ASSERT_EQ(Type::min_sub_types, 0);
            ASSERT_EQ(Type::max_sub_types, 0);
            ASSERT_EQ(Type::typeKind, pb::TypeKind::TYPE_KIND_DATETIME);
            ASSERT_EQ(Type::primitive_type, PrimitiveType::TIME | PrimitiveType::PRIMITIVE);
            ASSERT_EQ(Type::is_fixed_width, true);
            ASSERT_EQ(std::string(Type::name), "DATETIME");
        }
        /// INTERVAL
        {
            using Type = TypeTraits<pb::TypeKind::TYPE_KIND_INTERVAL>;
            ASSERT_TRUE((std::is_same_v<Type::impl_type, IntervalType>));
            ASSERT_TRUE((std::is_same_v<Type::physical_type, turbo::CivilSecond>));
            ASSERT_TRUE((std::is_same_v<Type::deep_copied_type, int64_t>));
            ASSERT_EQ(Type::min_sub_types, 0);
            ASSERT_EQ(Type::max_sub_types, 0);
            ASSERT_EQ(Type::typeKind, pb::TypeKind::TYPE_KIND_INTERVAL);
            ASSERT_EQ(Type::primitive_type, PrimitiveType::TIME | PrimitiveType::PRIMITIVE);
            ASSERT_EQ(Type::is_fixed_width, true);
            ASSERT_EQ(std::string(Type::name), "INTERVAL");
        }
        /// DECIMAL64
        {
            using Type = TypeTraits<pb::TypeKind::TYPE_KIND_DECIMAL64>;
            ASSERT_TRUE((std::is_same_v<Type::impl_type, DecimalType<pb::TypeKind::TYPE_KIND_DECIMAL64>>));
            ASSERT_TRUE((std::is_same_v<Type::physical_type, uint64_t>));
            ASSERT_TRUE((std::is_same_v<Type::deep_copied_type, uint64_t>));
            ASSERT_EQ(Type::min_sub_types, 0);
            ASSERT_EQ(Type::max_sub_types, 0);
            ASSERT_EQ(Type::typeKind, pb::TypeKind::TYPE_KIND_DECIMAL64);
            ASSERT_EQ(Type::primitive_type, PrimitiveType::DECIMAL | PrimitiveType::PRIMITIVE);
            ASSERT_EQ(Type::is_fixed_width, true);
            ASSERT_EQ(std::string(Type::name), "DECIMAL64");
        }

        /// DECIMAL128
        {
            using Type = TypeTraits<pb::TypeKind::TYPE_KIND_DECIMAL128>;
            ASSERT_TRUE((std::is_same_v<Type::impl_type, DecimalType<pb::TypeKind::TYPE_KIND_DECIMAL128>>));
            ASSERT_TRUE((std::is_same_v<Type::physical_type, turbo::uint128>));
            ASSERT_TRUE((std::is_same_v<Type::deep_copied_type, turbo::uint128>));
            ASSERT_EQ(Type::min_sub_types, 0);
            ASSERT_EQ(Type::max_sub_types, 0);
            ASSERT_EQ(Type::typeKind, pb::TypeKind::TYPE_KIND_DECIMAL128);
            ASSERT_EQ(Type::primitive_type, PrimitiveType::DECIMAL | PrimitiveType::PRIMITIVE);
            ASSERT_EQ(Type::is_fixed_width, true);
            ASSERT_EQ(std::string(Type::name), "DECIMAL128");
        }
        /// ENUM
        {
            using Type = TypeTraits<pb::TypeKind::TYPE_KIND_ENUM>;
            ASSERT_TRUE((std::is_same_v<Type::impl_type, EnumType>));
            ASSERT_TRUE((std::is_same_v<Type::physical_type, uint32_t>));
            ASSERT_TRUE((std::is_same_v<Type::deep_copied_type, uint32_t>));
            ASSERT_EQ(Type::min_sub_types, 0);
            ASSERT_EQ(Type::max_sub_types, 0);
            ASSERT_EQ(Type::typeKind, pb::TypeKind::TYPE_KIND_ENUM);
            ASSERT_EQ(Type::primitive_type, PrimitiveType::ENUM | PrimitiveType::PRIMITIVE);
            ASSERT_EQ(Type::is_fixed_width, true);
            ASSERT_EQ(std::string(Type::name), "ENUM");
        }
        /// ARRAY
        {
            using Type = TypeTraits<pb::TypeKind::TYPE_KIND_ARRAY>;
            ASSERT_TRUE((std::is_same_v<Type::impl_type, ArrayType>));
            ASSERT_TRUE((std::is_same_v<Type::physical_type, turbo::span<uint8_t>>));
            ASSERT_TRUE((std::is_same_v<Type::deep_copied_type, turbo::span<uint8_t>>));
            ASSERT_EQ(Type::min_sub_types, 1);
            ASSERT_EQ(Type::max_sub_types, 1);
            ASSERT_EQ(Type::typeKind, pb::TypeKind::TYPE_KIND_ARRAY);
            ASSERT_EQ(Type::primitive_type, PrimitiveType::DEFAULT);
            ASSERT_EQ(Type::is_fixed_width, false);
            ASSERT_EQ(std::string(Type::name), "ARRAY");
        }
        /// MAP
        {
            using Type = TypeTraits<pb::TypeKind::TYPE_KIND_MAP>;
            ASSERT_TRUE((std::is_same_v<Type::impl_type, MapType>));
            ASSERT_TRUE((std::is_same_v<Type::physical_type, std::map<int32_t, int32_t>>));
            ASSERT_TRUE((std::is_same_v<Type::deep_copied_type, turbo::span<uint8_t>>));
            ASSERT_EQ(Type::min_sub_types, 2);
            ASSERT_EQ(Type::max_sub_types, 2);
            ASSERT_EQ(Type::typeKind, pb::TypeKind::TYPE_KIND_MAP);
            ASSERT_EQ(Type::primitive_type, PrimitiveType::DEFAULT);
            ASSERT_EQ(Type::is_fixed_width, false);
            ASSERT_EQ(std::string(Type::name), "MAP");
        }
        /// SET
        {
            using Type = TypeTraits<pb::TypeKind::TYPE_KIND_SET>;
            ASSERT_TRUE((std::is_same_v<Type::impl_type, SetType>));
            ASSERT_TRUE((std::is_same_v<Type::physical_type, std::set<int32_t>>));
            ASSERT_TRUE((std::is_same_v<Type::deep_copied_type, turbo::span<uint8_t>>));
            ASSERT_EQ(Type::min_sub_types, 1);
            ASSERT_EQ(Type::max_sub_types, 1);
            ASSERT_EQ(Type::typeKind, pb::TypeKind::TYPE_KIND_SET);
            ASSERT_EQ(Type::primitive_type, PrimitiveType::DEFAULT);
            ASSERT_EQ(Type::is_fixed_width, false);
            ASSERT_EQ(std::string(Type::name), "SET");
        }

        /// STRUCT
        {
            using Type = TypeTraits<pb::TypeKind::TYPE_KIND_STRUCT>;
            ASSERT_TRUE((std::is_same_v<Type::impl_type, StructType>));
            ASSERT_TRUE((std::is_same_v<Type::physical_type, std::shared_ptr<void>>));
            ASSERT_TRUE((std::is_same_v<Type::deep_copied_type, turbo::span<uint8_t>>));
            ASSERT_EQ(Type::min_sub_types, 1);
            ASSERT_EQ(Type::max_sub_types, std::numeric_limits<uint32_t>::max());
            ASSERT_EQ(Type::typeKind, pb::TypeKind::TYPE_KIND_STRUCT);
            ASSERT_EQ(Type::primitive_type, PrimitiveType::DEFAULT);
            ASSERT_EQ(Type::is_fixed_width, false);
            ASSERT_EQ(std::string(Type::name), "STRUCT");
        }
        /// TUPLE
        {
            using Type = TypeTraits<pb::TypeKind::TYPE_KIND_TUPLE>;
            ASSERT_TRUE((std::is_same_v<Type::impl_type, TupleType>));
            ASSERT_TRUE((std::is_same_v<Type::physical_type, std::shared_ptr<void>>));
            ASSERT_TRUE((std::is_same_v<Type::deep_copied_type, turbo::span<uint8_t>>));
            ASSERT_EQ(Type::min_sub_types, 1);
            ASSERT_EQ(Type::max_sub_types, std::numeric_limits<uint32_t>::max());
            ASSERT_EQ(Type::typeKind, pb::TypeKind::TYPE_KIND_TUPLE);
            ASSERT_EQ(Type::primitive_type, PrimitiveType::DEFAULT);
            ASSERT_EQ(Type::is_fixed_width, false);
            ASSERT_EQ(std::string(Type::name), "TUPLE");
        }
        /// UNION
        {
            using Type = TypeTraits<pb::TypeKind::TYPE_KIND_UNION>;
            ASSERT_TRUE((std::is_same_v<Type::impl_type, UnionType>));
            ASSERT_TRUE((std::is_same_v<Type::physical_type, std::shared_ptr<void>>));
            ASSERT_TRUE((std::is_same_v<Type::deep_copied_type, turbo::span<uint8_t>>));
            ASSERT_EQ(Type::min_sub_types, 1);
            ASSERT_EQ(Type::max_sub_types, std::numeric_limits<uint32_t>::max());
            ASSERT_EQ(Type::typeKind, pb::TypeKind::TYPE_KIND_UNION);
            ASSERT_EQ(Type::primitive_type, PrimitiveType::DEFAULT);
            ASSERT_EQ(Type::is_fixed_width, false);
            ASSERT_EQ(std::string(Type::name), "UNION");
        }
        /// JSON
        {
            using Type = TypeTraits<pb::TypeKind::TYPE_KIND_JSON>;
            ASSERT_TRUE((std::is_same_v<Type::impl_type, JsonType>));
            ASSERT_TRUE((std::is_same_v<Type::physical_type, std::shared_ptr<void>>));
            ASSERT_TRUE((std::is_same_v<Type::deep_copied_type, std::string>));
            ASSERT_EQ(Type::min_sub_types, 0);
            ASSERT_EQ(Type::max_sub_types, 0);
            ASSERT_EQ(Type::typeKind, pb::TypeKind::TYPE_KIND_JSON);
            ASSERT_EQ(Type::primitive_type, PrimitiveType::DEFAULT);
            ASSERT_EQ(Type::is_fixed_width, false);
            ASSERT_EQ(std::string(Type::name), "JSON");
        }

        /// PROTO
        {
            using Type = TypeTraits<pb::TypeKind::TYPE_KIND_PROTO>;
            ASSERT_TRUE((std::is_same_v<Type::impl_type, ProtoType>));
            ASSERT_TRUE((std::is_same_v<Type::physical_type, std::shared_ptr<void>>));
            ASSERT_TRUE((std::is_same_v<Type::deep_copied_type, std::string>));
            ASSERT_EQ(Type::min_sub_types, 0);
            ASSERT_EQ(Type::max_sub_types, 0);
            ASSERT_EQ(Type::typeKind, pb::TypeKind::TYPE_KIND_PROTO);
            ASSERT_EQ(Type::primitive_type, PrimitiveType::DEFAULT);
            ASSERT_EQ(Type::is_fixed_width, false);
            ASSERT_EQ(std::string(Type::name), "PROTO");
        }

        /// UDF
        {
            using Type = TypeTraits<pb::TypeKind::TYPE_KIND_UDF>;
            ASSERT_TRUE((std::is_same_v<Type::impl_type, UdfType>));
            ASSERT_TRUE((std::is_same_v<Type::physical_type, std::shared_ptr<void>>));
            ASSERT_TRUE((std::is_same_v<Type::deep_copied_type, std::shared_ptr<void>>));
            ASSERT_EQ(Type::min_sub_types, 0);
            ASSERT_EQ(Type::max_sub_types, 0);
            ASSERT_EQ(Type::typeKind, pb::TypeKind::TYPE_KIND_UDF);
            ASSERT_EQ(Type::primitive_type, PrimitiveType::DEFAULT);
            ASSERT_EQ(Type::is_fixed_width, false);
            ASSERT_EQ(std::string(Type::name), "UDF");
        }
    }
}  // namespace cantor

